/******************************************************************************
******************************************************************************
* Knorr-Bremse * (c) Knorr-Bremse reserves all rights even in the *
* SfN GmbH * event of industrial property. We reserve all rights *
* Electronic Systems * of disposal such as copying and passing on to *
* * third parties. *
******************************************************************************
* History *
* -------------------------------------------------------------------------- *
* sample implementation *
******************************************************************************
* Short description *
* ----------------------------------------------------------------------------
* Sample implementation of seed&key algorithm used for Keyword Protocol 2000 *
******************************************************************************
* To-Do *
* ----------------------------------------------------------------------------
* End-To-Do *
******************************************************************************
******************************************************************************
*/
/* type definitions */
typedef unsigned char uint8;
typedef unsigned long uint32;
typedef int bool;
typedef signed char sint8;
#define FALSE 0
#define TRUE 1
#define BIT7 0x080
/* Return values of compareKey-functions: */
#define UKEY_ST_OK 0x00 /* Keys are identical */
#define UKEY_ST_INVLENGTH 0x11 /* Invalid length of given key */
#define UKEY_ST_INVKEY 0x22 /* Keys are different */
/* Configuration structure: */
typedef struct {
	uint8 dLength; /* Size of mask (number of bytes) */
	uint8 numShifts; /* Number of shifts */
	uint8 dMask[255]; /* Mask for CRC algorithm */
} UKey_CrcConf;
/* Macros for configuration of CRC seed & key algorithm: */
#define UKEY_CRCMASK_START(name, size, shifts) \
struct { \
	uint8 dLength; \
	uint8 numShifts; \
	uint8 dMask[size]; \
} const name = \
{ size, \
	shifts, \
{
#define UKEY_CRCMASK_END() }};
/* definition of algorithm parameters (example only) */
UKEY_CRCMASK_START(UKey_CrcMask1, 4, 21)
	0xD0, 0x20, 0x0D, 0x62
	UKEY_CRCMASK_END()
	/* Maximum size of seed and key (needed for size of array): */
	/* must be adapted to used parameters */
#define UKEY_NUM_MAX 0x04 /* Size of UKey_dSeed[], Ukey_dKey[] */
	/* RAM for current seed (maximum size depends on configuration) */
	uint8 UKey_dSeed[UKEY_NUM_MAX];
/* RAM for current key (maximum size depends on configuration) */
uint8 UKey_dKey[UKEY_NUM_MAX];
/* takes a given seed value (UKey_dSeed) and a configuration structure */
/* (Config_pcs) and calculates a key value (written to UKey_dKey) */
uint8 UKey_CalculateKey_Crc (UKey_CrcConf* Config, uint8 dLength)
{
	uint8 stRetVal; /* Return value */
	static uint8 ct; /* Counter */
	static uint8 numShifts; /* Number of shifts */
	bool stCarry; /* True: Carry is set */
	/* start only if seed has the right length */
	if(Config->dLength == dLength && dLength <= UKEY_NUM_MAX)
	{
		/* Copy seed to key: */
		for(ct = 0; ct < dLength; ct++ )
			UKey_dKey[ct] = UKey_dSeed[ct];
		/* Calculation of key / Count shifts: */
		for(numShifts = Config->numShifts; numShifts > 0; numShifts-- )
		{
			/* Shift key left with carry bit by number of shifts */
			for(stCarry = FALSE, ct = dLength - 1; (sint8)ct >= 0; ct-- )
			{
				if(stCarry)
				{
					/* Get next carry bit: */
					stCarry= ((UKey_dKey[ct] & BIT7) != 0);
					/* Shift key with carry: */
					UKey_dKey[ct]= (UKey_dKey[ct] << 1) + 1;
				}
				else
				{
					/* Get next carry bit: */
					stCarry = ((UKey_dKey[ct] & BIT7) != 0);
					/* Shift key without carry bit: */
					UKey_dKey[ct] <<= 1;
				}
			}
			/* XOR current value of key with mask if carry set */
			if(stCarry)
				for(ct = 0; ct < dLength; ct++ )
					UKey_dKey[ct] ^= Config->dMask[ct];
		}
		stRetVal = UKEY_ST_OK;
	}
	else
	{
		stRetVal = UKEY_ST_INVLENGTH;
	}
	return(stRetVal);
}
/* compares a given key value (dKey) with a */
/* calculated value (UKey_dKey) */
uint8 UKey_CompareKey_Crc (UKey_CrcConf* Config, uint8* dKey, uint8 dLength)
{
	uint8 stRetVal; /* Return value */
	static uint8 ct; /* Counter */
	/* start only if length of parameters match */
	if(Config->dLength == dLength && dLength <= UKEY_NUM_MAX)
	{
		/* Compare keys: */
		for(ct = 0; (ct < dLength)&&(dKey[ct] == UKey_dKey[ct]); ct++);
		if(ct < dLength)
		{
			stRetVal = UKEY_ST_INVKEY;
		}
		else
		{
			stRetVal = UKEY_ST_OK;
		}
	}
	else
	{
		stRetVal = UKEY_ST_INVLENGTH;
	}
	return(stRetVal);
}

int main ()
{
	uint8 RetVal;
	/* defined length of seed&key */
	uint8 length = 4;
	/* sample key provided by other entity */
	uint8 dKey[4] = {0x02,0x34,0x45,0x78};
	/* sample seed to start algorithm */
	UKey_dSeed[0] = 0x83;
	UKey_dSeed[1] = 0xf9;
	UKey_dSeed[2] = 0x6f;
	UKey_dSeed[3] = 0xe5;
	/* calculate a key from a given seed, */
	/* seed: UKey_dSeed */
	/* key: UKey_dKey */
	/* use UKey_CrcMask1 for configuration */
	/* size of seed / Key is 4 */
	printf("%02X-%02X-%02X-%02X\n", UKey_dKey[0], UKey_dKey[1], UKey_dKey[2], UKey_dKey[1]);
	RetVal = UKey_CalculateKey_Crc((UKey_CrcConf* )&UKey_CrcMask1, length);
	printf("%02X-%02X-%02X-%02X\n", UKey_dKey[0], UKey_dKey[1], UKey_dKey[2], UKey_dKey[1]);
	/* compare calculated key with test value */
	/* key: UKey_dKey */
	/* test key: dKey */
	RetVal = UKey_CompareKey_Crc((UKey_CrcConf* )&UKey_CrcMask1, dKey, length);
	printf("%02X-%02X-%02X-%02X\n", UKey_dKey[0], UKey_dKey[1], UKey_dKey[2], UKey_dKey[1]);
}